﻿/*
	* Project	: SharePoint Dynamic Forms
	* Version	: 1.0
	* Company	: SharePoint Frontier Software Pvt Ltd. (http://www.sharepointfrontier.com)
	* Author	: Ashok Raja .T (Blog : http://www.ashokraja.me)
	* Licence	: Published under Microsoft Public License (Ms-PL)
*/
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.SharePoint.Utilities;

namespace SFS.SharePoint.DynamicForms
{
    public partial class DynamicForm : UserControl
    {
        public delegate void ItemAdded(SPListItem item);
        public event ItemAdded OnItemAdded;

        public delegate void ItemAdding(SPListItem item, DynamicFormEventArgs e);
        public event ItemAdding OnItemAdding;

        public string ListName { get; set; }
        public string FormTitle { get; set; }
        public string TemplateSourceList { get; set; }
        public string TemplateID { get; set; }
        public string TemplateIDColumn { get; set; }
        public string TemplateDataColumn { get; set; }
        public string SaveUrl { get; set; }
        public string CancelUrl { get; set; }
        public RenderMode RenderingMode { get; set; }
        public TemplateMode RenderingTemplate { get; set; }
        public bool DisplayContentType { get; set; }
        public int ItemId { get; set; }
        public string IgnoreFields { get; set; }
        public string ShowFields { get; set; }
        public bool ShowCancel { get; set; }
        public bool ShowHeader { get; set; }
        public string SaveCaption { get; set; }
        public string CancelCaption { get; set; }
        public int SaveButtonWidth { get; set; }
        public int CancelButtonWidth { get; set; }
        public bool CloseFormOnSubmit { get; set; }

        SPListItem CurrentItem = null;

        public enum TemplateMode
        {
            List,
            Template
        }

        public enum RenderMode
        {
            New,
            Edit,
            Display
        }

        protected void Page_Load(object sender, EventArgs e)
        {
        }

        //protected override void OnInit(EventArgs e)
        //{
        //    base.OnInit(e);
        //    RenderDynamicDataControls("T2", "FormTemplates");
        //}

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            if (RenderingTemplate == TemplateMode.List)
                RenderDynamicDataControls(this.ListName);
            else
                RenderDynamicDataControls(this.TemplateID, this.TemplateIDColumn, this.TemplateDataColumn, this.TemplateSourceList);
        }
        private void RenderDynamicDataControls(string templateID, string templateIDColumn, string templateDataColumn, string templateSourceList)
        {
            try
            {

                WebPartManager wp = WebPartManager.GetCurrentWebPartManager(Page);
                if (wp.DisplayMode != WebPartManager.BrowseDisplayMode)
                {
                    DataContainer.Visible = false;
                    lblError.Text = "";
                    ltStatus.Text = "Please configure the webpart to render content ....";
                    return;
                }
                else
                {
                    ltStatus.Text = "";
                    DataContainer.Visible = true;
                }
                if (Table1 == null) return;
                Table1.Controls.Clear();
                RenderUserSettings();
                SPDynamicForm Frm = new SPDynamicForm(templateID, templateIDColumn, templateDataColumn, templateSourceList);
                ltTitle.Text = Frm.FormName;
                SPSecurity.RunWithElevatedPrivileges(delegate()
                       {
                           using (SPSite site = new SPSite(SPContext.Current.Site.Url))
                           {
                               site.AllowUnsafeUpdates = true;
                               using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
                               {
                                   SPList list = web.Lists[Frm.ListName];
                                   SPControl.SetContextWeb(HttpContext.Current, web);
                                   foreach (SPDynamicField item in Frm.GetFormFields())
                                   {
                                       Label lbl = new Label();
                                       lbl.Text = RenderLabel(item.DisplayName, item.IsRequired);

                                       if (!string.IsNullOrEmpty(item.DisplayMode) && item.DisplayMode.ToLower() == "view")
                                       {
                                           Label ctl = new Label();
                                           ctl.Text = item.DefaultValue;
                                           AddNewRow(lbl, ctl);
                                       }
                                       else
                                       {
                                           FormField fld = new FormField();
                                           fld.ControlMode = GetRenderMode();
                                           fld.ListId = list.ID;
                                           if (fld.ControlMode == SPControlMode.Edit)
                                               fld.ItemId = this.ItemId;
                                           //fld.ItemId = fld.ControlMode == SPControlMode.Edit ? ItemId : -1;
                                           fld.FieldName = item.InternalName;
                                           fld.ID = GenericHelper.CONTROL_IDENTIFIER + item.InternalName;
                                           if (!string.IsNullOrEmpty(item.DefaultValue)) fld.Value = item.DefaultValue;
                                           AddNewRow(lbl, fld);
                                       }

                                   }
                               }
                           }
                       }
                );
            }
            catch (Exception Ex)
            {
                DataContainer.Visible = false;
                ErrorContainer.Visible = true;
                lblError.Text = Ex.Message + "<br/>" + Ex.StackTrace;
            }

        }

        private SPControlMode GetRenderMode()
        {
            switch (this.RenderingMode)
            {
                case RenderMode.New:
                    return SPControlMode.New;
                case RenderMode.Edit:
                    return SPControlMode.Edit;
                case RenderMode.Display:
                    return SPControlMode.Display;
                default:
                    return SPControlMode.New;
            }
        }

        //public void OnUpdating()
        //{

        //}

        //public void OnUpdateComplete()
        //{

        //}

        private void RenderDynamicDataControls(string ListName)
        {

            try
            {

                WebPartManager wp = WebPartManager.GetCurrentWebPartManager(Page);
                if (wp.DisplayMode != WebPartManager.BrowseDisplayMode)
                {
                    DataContainer.Visible = false;
                    return;
                }
                else
                {
                    DataContainer.Visible = true;
                }
                Table1.Rows.Clear();
                lblError.Text = "";
                RenderUserSettings();
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    using (SPSite site = new SPSite(SPContext.Current.Site.ID))
                    {
                        site.AllowUnsafeUpdates = true;
                        using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
                        {
                            SPList list = web.Lists[ListName];
                            ltTitle.Text = this.FormTitle ?? list.Title;

                            SPControl.SetContextWeb(HttpContext.Current, web);
                            foreach (SPField item in list.Fields)
                            {
                                if (!item.Hidden && !item.ReadOnlyField && item.Type != SPFieldType.Attachments && item.Type != SPFieldType.File)
                                {
                                    if (!DisplayContentType && item.InternalName == "ContentType")
                                        continue;

                                    if (!IsFieldToBeShown(item.InternalName))
                                        continue;

                                    if (IsFieldToBeIgnored(item.InternalName))
                                        continue;
                                    Label lbl = new Label();
                                    lbl.Text = RenderLabel(item.Title, item.Required);
                                    //SPContext ctlContext = SPContext.GetContext(this.Context, UniqueId + item.InternalName, list.ID, web);
                                    FormField fld = new FormField();

                                    fld.ControlMode = GetRenderMode();
                                    fld.ListId = list.ID;
                                    fld.FieldName = item.InternalName;
                                    fld.ID = GenericHelper.CONTROL_IDENTIFIER + item.InternalName;
                                    //fld.ItemContext = ctlContext;
                                    //fld.RenderContext = ctlContext;
                                    AddNewRow(lbl, fld);
                                }

                            }
                        }
                    }
                }
                );
            }
            catch (Exception Ex)
            {
                DataContainer.Visible = false;
                ErrorContainer.Visible = true;
                lblError.Text = Ex.Message + "<br/>" + Ex.StackTrace;
            }

        }

        private bool IsFieldToBeIgnored(string FieldName)
        {
            try
            {
                if (string.IsNullOrEmpty(IgnoreFields))
                    return false;
                string[] IgnoreItems = IgnoreFields.Split(',');
                return IgnoreItems.Contains(FieldName);
            }
            catch
            {
                return false;
            }
        }

        private bool IsFieldToBeShown(string FieldName)
        {
            try
            {
                if (string.IsNullOrEmpty(ShowFields))
                    return true;
                string[] ShowFieldsItems = ShowFields.Split(',');
                return ShowFieldsItems.Contains(FieldName);
            }
            catch
            {
                return true;
            }
        }

        private List<FormField> FieldList()
        {
            List<FormField> Fields = new List<FormField>();
            SPSecurity.RunWithElevatedPrivileges(delegate()
               {
                   using (SPSite site = new SPSite(SPContext.Current.Site.ID))
                   {
                       site.AllowUnsafeUpdates = true;
                       using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
                       {
                           SPList list = web.Lists[ListName];
                           ltTitle.Text = list.Title;


                           foreach (SPField item in list.Fields)
                           {
                               if (!item.Hidden && !item.ReadOnlyField && item.Type != SPFieldType.Attachments && item.Type != SPFieldType.File)
                               {
                                   if (!DisplayContentType && item.InternalName == "ContentType")
                                       continue;

                                   if (!IsFieldToBeShown(item.InternalName))
                                       continue;

                                   if (IsFieldToBeIgnored(item.InternalName))
                                       continue;

                                   FormField formField = (FormField)this.FindControl(GenericHelper.CONTROL_IDENTIFIER + item.InternalName);
                                   if (formField == null) continue;
                                   Fields.Add(formField);
                               }
                           }
                       }
                   }
               });
            return Fields;
        }

        private void AddNewRow(Label lbl, FormField fld)
        {
            try
            {
                TableRow tr = new TableRow();
                AddLabelField(tr, lbl);
                AddFormField(tr, fld);
                Table1.Rows.Add(tr);
            }
            catch (Exception Ex)
            {

                throw;
            }
        }

        private void AddNewRow(Label lbl, Label ctl)
        {
            TableRow tr = new TableRow();
            AddLabelField(tr, lbl);
            AddValueField(tr, ctl);
            Table1.Rows.Add(tr);
        }

        private void AddLabelField(TableRow tr, Label lbl)
        {
            TableCell td = new TableCell();
            td.Controls.Add(lbl);
            td.CssClass = "CellSpacer";
            tr.Cells.Add(td);
        }

        private void AddValueField(TableRow tr, Label lbl)
        {
            TableCell td = new TableCell();
            td.Controls.Add(lbl);
            td.CssClass = "CellSpacer";
            tr.Cells.Add(td);
        }

        private void AddFormField(TableRow tr, FormField fld)
        {
            TableCell td = new TableCell();
            td.Controls.Add(fld);
            td.CssClass = "ms-formbody";
            td.Style.Add(HtmlTextWriterStyle.PaddingBottom, "10px");
            td.Style.Add(HtmlTextWriterStyle.PaddingLeft, "10px");
            tr.Cells.Add(td);
        }

        private string RenderLabel(string DisplayName, bool isRequired)
        {
            string Content = "<nobr>" + DisplayName;
            if (isRequired)
                Content += @"<span title=""This is a required field."" class=""ms-formvalidation""> *</span>";
            return Content += "</nobr>";
        }

        private ActivityResult InsertData()
        {
            if (this.RenderingTemplate == TemplateMode.List)
            {
                if (!Page.IsValid)
                    return new ActivityResult { IsSuccess = false };
                else
                    return AddListData();
            }
            else
                return AddTemplateData();

            //SPUtility.Redirect(SubmitButtonUrl, SPRedirectFlags.UseSource, HttpContext.Current);
        }

        private object GetFormData(SPDynamicField Fld)
        {
            if (string.IsNullOrEmpty(Fld.DisplayMode))
                return Fld.Value;

            return Fld.DisplayMode.ToLower() == "view" ? Fld.DefaultValue : Fld.Value;
        }

        private void UpdateUserInfo(SPListItem item)
        {
            SPFieldUserValueCollection fieldValues = new SPFieldUserValueCollection();
            SPUser user = SPContext.Current.Web.CurrentUser;
            fieldValues.Add(new SPFieldUserValue(item.Web, user.ID, user.Name));
            item["Author"] = fieldValues;
            item["Editor"] = fieldValues;
        }

        private ActivityResult AddListData()
        {
            ActivityResult Ar = new ActivityResult();
            try
            {
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    using (SPSite site = new SPSite(SPContext.Current.Site.Url))
                    {
                        site.AllowUnsafeUpdates = true;
                        using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
                        {
                            web.AllowUnsafeUpdates = true;

                            List<FormField> Flds = FieldList();
                            if (Flds.Count > 0)
                            {
                                SPList list = web.Lists[this.ListName];
                                SPListItem item = list.Items.Add();

                                foreach (FormField Fld in Flds)
                                {
                                    item[Fld.FieldName] = Fld.Value;
                                }
                                UpdateUserInfo(item);
                                DynamicFormEventArgs Args = new DynamicFormEventArgs();
                                OnItemAdding(item, Args);
                                if (!Args.Cancel)
                                {
                                    item.Update();
                                    OnItemAdded(item);
                                    Ar.IsSuccess = true;
                                }
                                else
                                {
                                    Ar.ErrorMessage = Args.CancelMessage;
                                }
                            }
                            web.AllowUnsafeUpdates = false;
                            site.AllowUnsafeUpdates = false;
                        }
                    }
                });

                return Ar;
            }
            catch (Exception Ex)
            {
                Ar.ErrorMessage = Ex.Message;
                return Ar;
            }
        }

        private ActivityResult AddTemplateData()
        {
            ActivityResult Ar = new ActivityResult();
            try
            {
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    using (SPSite site = new SPSite(SPContext.Current.Site.Url))
                    {
                        site.AllowUnsafeUpdates = true;
                        using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
                        {
                            web.AllowUnsafeUpdates = true;
                            SPDynamicFieldFieldValidationManger Val = new SPDynamicFieldFieldValidationManger(this.TemplateID, this.TemplateIDColumn, this.TemplateDataColumn, this.TemplateSourceList, this, GenericHelper.CONTROL_IDENTIFIER);
                            if (Val.IsValid() && Page.IsValid)
                            {
                                SPList list = web.Lists[Val.ListName];
                                SPListItem item = list.Items.Add();
                                foreach (SPDynamicField Field in Val.Fields)
                                {
                                    item[Field.InternalName] = GetFormData(Field);
                                }
                                UpdateUserInfo(item);
                                DynamicFormEventArgs Args = new DynamicFormEventArgs();
                                OnItemAdding(item, Args);
                                if (!Args.Cancel)
                                {
                                    item.Update();
                                    OnItemAdded(item);
                                    Ar.IsSuccess = true;
                                }
                                else
                                {
                                    Ar.ErrorMessage = Args.CancelMessage;
                                }
                            }
                            web.AllowUnsafeUpdates = false;
                            site.AllowUnsafeUpdates = false;
                        }
                    }
                });

                return Ar;
            }
            catch (Exception Ex)
            {
                Ar.ErrorMessage = Ex.Message;
                return Ar;
            }
        }

        protected void btnSave_Click(object sender, EventArgs e)
        {
            ActivityResult Ar = InsertData();
            if (Ar.IsSuccess)
            {
                if (this.CloseFormOnSubmit)
                {
                    ltStatus.Text = GenericHelper.ClosePopUp("OK");
                    return;
                }
                if (string.IsNullOrEmpty(this.SaveUrl))
                {
                    if (RenderingTemplate == TemplateMode.List)
                        RenderDynamicDataControls(this.ListName);
                    else
                        RenderDynamicDataControls(this.TemplateID, this.TemplateIDColumn, this.TemplateDataColumn, this.TemplateSourceList);

                    ltStatus.Text = GenericHelper.ShowStatus(Ar.SucessMessage ?? "Data successfully saved.", GenericHelper.InfoType.Success);
                }
                else
                    SPUtility.Redirect(GenericHelper.ParseUrl(this.SaveUrl), SPRedirectFlags.UseSource, HttpContext.Current);
            }
            else
                ltStatus.Text = GenericHelper.ShowStatus(Ar.ErrorMessage ?? "Failed to save data. Please re-check the input values.", GenericHelper.InfoType.Error);
        }

        protected void btncancel_Click(object sender, EventArgs e)
        {
            if (this.CloseFormOnSubmit)
            {
                ltStatus.Text = GenericHelper.ClosePopUp("Cancel");
                return;
            }
            if (string.IsNullOrEmpty(this.CancelUrl))
                SPUtility.Redirect(Request.RawUrl, SPRedirectFlags.UseSource, HttpContext.Current);
            else
                SPUtility.Redirect(GenericHelper.ParseUrl(this.CancelUrl), SPRedirectFlags.UseSource, HttpContext.Current);
        }



        private void RenderUserSettings()
        {
            btnSave.Text = string.IsNullOrEmpty(this.SaveCaption) ? "Save" : this.SaveCaption;
            btncancel.Text = string.IsNullOrEmpty(this.CancelCaption) ? "Cancel" : this.CancelCaption;
            btnSave.Width = this.SaveButtonWidth == 0 ? 125 : this.SaveButtonWidth;
            btncancel.Width = this.CancelButtonWidth == 0 ? 125 : this.CancelButtonWidth;
            btncancel.Visible = !this.ShowCancel;
            DataHeader.Visible = this.ShowHeader;
            //this.SaveUrl = this.SaveUrl ?? Request.RawUrl;
            //this.CancelUrl = this.CancelUrl ?? Request.RawUrl;

        }


    }
}
